import sys
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
                             QLabel, QPushButton, QLineEdit, QFileDialog, QMessageBox)
from PyQt5.QtGui import QPixmap, QImage
from PyQt5.QtCore import Qt
import cv2
import numpy as np


class ImageCalculatorApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("计算器与图像处理器")
        self.setGeometry(100, 100, 800, 600)

        # 初始化UI
        self.initUI()

        # 存储当前图像
        self.current_image = None
        self.original_image = None

        # 计算器相关变量
        self.calc_value = 0
        self.calc_operation = None
        self.calc_waiting_operand = False

    def initUI(self):
        # 主窗口部件
        main_widget = QWidget()
        self.setCentralWidget(main_widget)

        # 主布局
        main_layout = QHBoxLayout()
        main_widget.setLayout(main_layout)

        # 左侧计算器面板
        self.create_calculator(main_layout)

        # 右侧图像处理面板
        self.create_image_processor(main_layout)

    def create_calculator(self, parent_layout):
        # 计算器面板
        calc_panel = QWidget()
        calc_layout = QVBoxLayout()
        calc_panel.setLayout(calc_layout)
        parent_layout.addWidget(calc_panel, stretch=1)

        # 计算器显示
        self.calc_display = QLineEdit("0")
        self.calc_display.setAlignment(Qt.AlignRight)
        self.calc_display.setReadOnly(True)
        self.calc_display.setStyleSheet("font-size: 24px;")
        calc_layout.addWidget(self.calc_display)

        # 计算器按钮布局
        button_grid = QWidget()
        grid_layout = QVBoxLayout()
        button_grid.setLayout(grid_layout)

        # 第一行按钮
        row1 = QHBoxLayout()
        self.add_calc_button("7", row1)
        self.add_calc_button("8", row1)
        self.add_calc_button("9", row1)
        self.add_calc_button("/", row1)
        grid_layout.addLayout(row1)

        # 第二行按钮
        row2 = QHBoxLayout()
        self.add_calc_button("4", row2)
        self.add_calc_button("5", row2)
        self.add_calc_button("6", row2)
        self.add_calc_button("*", row2)
        grid_layout.addLayout(row2)

        # 第三行按钮
        row3 = QHBoxLayout()
        self.add_calc_button("1", row3)
        self.add_calc_button("2", row3)
        self.add_calc_button("3", row3)
        self.add_calc_button("-", row3)
        grid_layout.addLayout(row3)

        # 第四行按钮
        row4 = QHBoxLayout()
        self.add_calc_button("0", row4)
        self.add_calc_button(".", row4)
        self.add_calc_button("C", row4)
        self.add_calc_button("+", row4)
        grid_layout.addLayout(row4)

        # 第五行按钮
        row5 = QHBoxLayout()
        equals_btn = QPushButton("=")
        equals_btn.clicked.connect(self.calc_equals)
        equals_btn.setStyleSheet("font-size: 18px;")
        row5.addWidget(equals_btn)
        grid_layout.addLayout(row5)

        calc_layout.addWidget(button_grid)

        # 计算器到图像处理的转换按钮
        calc_to_img_btn = QPushButton("计算结果→图像处理")
        calc_to_img_btn.clicked.connect(self.use_calc_result_for_image)
        calc_layout.addWidget(calc_to_img_btn)

    def add_calc_button(self, text, layout):
        btn = QPushButton(text)
        btn.clicked.connect(lambda: self.calc_button_clicked(text))
        btn.setStyleSheet("font-size: 18px;")
        layout.addWidget(btn)

    def create_image_processor(self, parent_layout):
        # 图像处理面板
        img_panel = QWidget()
        img_layout = QVBoxLayout()
        img_panel.setLayout(img_layout)
        parent_layout.addWidget(img_panel, stretch=2)

        # 图像显示
        self.image_label = QLabel()
        self.image_label.setAlignment(Qt.AlignCenter)
        self.image_label.setStyleSheet("border: 1px solid black;")
        img_layout.addWidget(self.image_label, stretch=1)

        # 图像处理按钮
        btn_row1 = QHBoxLayout()
        self.add_img_button("打开图片", self.open_image, btn_row1)
        self.add_img_button("灰度处理", self.gray_image, btn_row1)
        self.add_img_button("重置图片", self.reset_image, btn_row1)
        img_layout.addLayout(btn_row1)

        btn_row2 = QHBoxLayout()
        self.add_img_button("模糊处理", self.blur_image, btn_row2)
        self.add_img_button("边缘检测", self.edge_image, btn_row2)
        self.add_img_button("亮度调整", self.adjust_brightness, btn_row2)
        img_layout.addLayout(btn_row2)

        # 图像到计算器的转换按钮
        img_to_calc_btn = QPushButton("图像参数→计算器")
        img_to_calc_btn.clicked.connect(self.use_image_info_for_calc)
        img_layout.addWidget(img_to_calc_btn)

    def add_img_button(self, text, function, layout):
        btn = QPushButton(text)
        btn.clicked.connect(function)
        layout.addWidget(btn)

    # 计算器功能
    def calc_button_clicked(self, text):
        if text.isdigit() or text == '.':
            if self.calc_waiting_operand:
                self.calc_display.setText(text)
                self.calc_waiting_operand = False
            else:
                if self.calc_display.text() == '0' and text != '.':
                    self.calc_display.setText(text)
                else:
                    self.calc_display.setText(self.calc_display.text() + text)
        elif text == 'C':
            self.calc_display.setText('0')
            self.calc_value = 0
            self.calc_operation = None
            self.calc_waiting_operand = False
        else:  # 运算符
            self.calc_value = float(self.calc_display.text())
            self.calc_operation = text
            self.calc_waiting_operand = True

    def calc_equals(self):
        if self.calc_operation:
            operand = float(self.calc_display.text())
            if self.calc_operation == '+':
                result = self.calc_value + operand
            elif self.calc_operation == '-':
                result = self.calc_value - operand
            elif self.calc_operation == '*':
                result = self.calc_value * operand
            elif self.calc_operation == '/':
                try:
                    result = self.calc_value / operand
                except ZeroDivisionError:
                    QMessageBox.warning(self, "错误", "不能除以零!")
                    return

            self.calc_display.setText(str(result))
            self.calc_value = 0
            self.calc_operation = None
            self.calc_waiting_operand = True

    # 图像处理功能
    def open_image(self):
        file_name, _ = QFileDialog.getOpenFileName(self, "选择图片", "", "图片文件 (*.png *.jpg *.jpeg *.bmp)")
        if file_name:
            self.original_image = cv2.imread(file_name)
            self.current_image = self.original_image.copy()
            self.show_image(self.current_image)

    def show_image(self, image):
        if len(image.shape) == 3:  # 彩色图像
            height, width, channel = image.shape
            bytes_per_line = 3 * width
            q_img = QImage(image.data, width, height, bytes_per_line, QImage.Format_BGR888)
        else:  # 灰度图像
            height, width = image.shape
            q_img = QImage(image.data, width, height, width, QImage.Format_Grayscale8)

        pixmap = QPixmap.fromImage(q_img)
        self.image_label.setPixmap(pixmap.scaled(
            self.image_label.width(), self.image_label.height(),
            Qt.KeepAspectRatio, Qt.SmoothTransformation
        ))

    def gray_image(self):
        if self.current_image is not None:
            gray = cv2.cvtColor(self.current_image, cv2.COLOR_BGR2GRAY)
            self.current_image = gray
            self.show_image(gray)

    def blur_image(self):
        if self.current_image is not None:
            blurred = cv2.GaussianBlur(self.current_image, (15, 15), 0)
            self.current_image = blurred
            self.show_image(blurred)

    def edge_image(self):
        if self.current_image is not None:
            if len(self.current_image.shape) == 3:
                gray = cv2.cvtColor(self.current_image, cv2.COLOR_BGR2GRAY)
            else:
                gray = self.current_image
            edges = cv2.Canny(gray, 100, 200)
            self.current_image = edges
            self.show_image(edges)

    def adjust_brightness(self):
        if self.current_image is not None:
            try:
                value = float(self.calc_display.text())
                value = max(-100, min(100, value))  # 限制范围
                brightened = cv2.convertScaleAbs(self.current_image, alpha=1, beta=value)
                self.current_image = brightened
                self.show_image(brightened)
            except ValueError:
                QMessageBox.warning(self, "错误", "请输入有效的亮度值!")

    def reset_image(self):
        if self.original_image is not None:
            self.current_image = self.original_image.copy()
            self.show_image(self.current_image)

    # 交互功能
    def use_calc_result_for_image(self):
        if self.current_image is not None:
            try:
                value = float(self.calc_display.text())
                self.adjust_brightness()
            except ValueError:
                QMessageBox.warning(self, "错误", "计算器中没有有效数值!")

    def use_image_info_for_calc(self):
        if self.current_image is not None:
            if len(self.current_image.shape) == 3:
                avg_color = np.mean(self.current_image, axis=(0, 1))
                self.calc_display.setText(f"{avg_color[0]:.1f}")
            else:
                avg_value = np.mean(self.current_image)
                self.calc_display.setText(f"{avg_value:.1f}")


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = ImageCalculatorApp()
    window.show()
    sys.exit(app.exec_())